package com.xdja.jwt.imagecollect.mvp.model

import android.app.Application
import com.blankj.utilcode.util.CacheDoubleUtils
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.Utils
import com.google.gson.Gson
import com.jess.arms.di.scope.FragmentScope
import com.jess.arms.integration.IRepositoryManager
import com.jess.arms.mvp.BaseModel
import com.xdja.jwt.imagecollect.app.bean.Reload
import com.xdja.jwt.imagecollect.app.bean.User
import com.xdja.jwt.imagecollect.app.db.database.DatabaseManager
import com.xdja.jwt.imagecollect.app.db.entity.DownloadFileBean
import com.xdja.jwt.imagecollect.app.ext.getFastDfsUrl
import com.xdja.jwt.imagecollect.app.net.FilesApi
import com.xdja.jwt.imagecollect.app.utils.Constant
import com.xdja.jwt.imagecollect.mvp.contract.DownloadingContract
import io.reactivex.Flowable
import kotlinx.coroutines.*
import org.simple.eventbus.EventBus
import java.io.File
import javax.inject.Inject
import kotlin.coroutines.EmptyCoroutineContext


/**
 * @author yuanwanli
 * @date 2019/11/11
 * @des
 */
@FragmentScope
class DownloadingModel
@Inject
constructor(repositoryManager: IRepositoryManager) : BaseModel(repositoryManager),
    DownloadingContract.Model {

    @Inject
    lateinit var mGson: Gson
    @Inject
    lateinit var mApplication: Application
    private var scopeMap: MutableMap<Int, CoroutineScope> = mutableMapOf()

    companion object {
        const val WRITEMAX = 1024 * 100
    }
    override fun getAllDownloadingBean(): Flowable<List<DownloadFileBean>> {
        val user = CacheDoubleUtils.getInstance().getParcelable(Constant.LOGIN_CACHE, User.CREATOR)
        return DatabaseManager.getInstance(Utils.getApp()).fileDao().getAllDownloadBean(user.id, 0)
    }

    override fun downloadBean(it: DownloadFileBean) {
        val scope = CoroutineScope(EmptyCoroutineContext)
        val bean = it.copy()
        scopeMap[it.id] = scope
        bean.hasStart = true
        bean.hasError = false
        DatabaseManager.getInstance(mApplication).fileDao().insertOrUpdateDownloadBean(bean)
        scope.launch {
            async {
                var file = File(bean.filePath)
                if (FileUtils.createOrExistsFile(file)) {
                    startDownload(file, bean)
                }
            }
        }
    }

    private suspend fun startDownload(file: File, bean: DownloadFileBean) {
        try {
            var start: Long = 0L
            if (file.length() != 0L) {
                start = file.length()
            }
            var end: Long = start + WRITEMAX - 1
            if (end > bean.totalSize) {
                end = bean.totalSize - 1
            }
            val downloadPartial = mRepositoryManager.obtainRetrofitService(FilesApi::class.java)
                .downloadPartial(bean.downloadUrl.getFastDfsUrl(), "bytes=$start-$end")
            file.appendBytes(downloadPartial.bytes())
            bean.downloadSize = file.length()
            if (bean.downloadSize >= bean.totalSize) {
                bean.state = 1
                DatabaseManager.getInstance(mApplication).fileDao().insertOrUpdateDownloadBean(bean)
                EventBus.getDefault().post(Reload())
            } else {
                DatabaseManager.getInstance(mApplication).fileDao().insertOrUpdateDownloadBean(bean)
                startDownload(file, bean)
            }
        } catch (e: Exception) {
            LogUtils.e(e)
            if (e !is CancellationException) {
                bean.hasError = true
            }
            bean.hasStart = false
            DatabaseManager.getInstance(Utils.getApp()).fileDao().insertOrUpdateDownloadBean(bean)
        }
    }

    override fun stopDownloadBean(bean: DownloadFileBean) {
        val scope = scopeMap[bean.id]
        scope?.cancel()
        scopeMap.remove(bean.id)
    }
    override fun onDestroy() {
        super.onDestroy()
        scopeMap.forEach {
            it.value.cancel()
        }
        scopeMap.clear()
    }
}
